#include "CustomBoxView.h"
#include <QPushButton>
#include <QEvent>
#include <QPainter>
#include <QMutexLocker>
#include <QResizeEvent>
#include <QScrollArea>
#include <QScrollBar>

#include "glog/logging.h"

#define DEFAULT_MAX_BOX_CNT			200
#define DEFAULT_CELL_HEIGHT			70
#define DEFAULT_CELL_WIDHT			140
#define DEFAULT_SPACING				8

CCustomBoxCell::CCustomBoxCell(QWidget* parent)
	: QPushButton(parent)
	, is_visiable_(false)
{

}

CCustomBoxCell::~CCustomBoxCell()
{

}

QString CCustomBoxCell::get_locker_no_string(int32_t no)
{
    auto sno = QString("%1").arg(no);
	return sno;
}

QString CCustomBoxCell::get_locker_size_string(int32_t size)
{
	switch (locker_.type)
	{
    case zl::ELockerType_Small:         return tr("S");
    case zl::ELockerType_Medium:        return tr("M");
    case zl::ELockerType_Large:         return tr("L");
    case zl::ELockerType_ExtraLarge:	return tr("E");
	default:	return "";
	}
}

void CCustomBoxCell::paintEvent(QPaintEvent * e)
{
	if (!is_visiable_) return;

	QRect rect = this->rect();

	QPainter p(this);
	p.setRenderHint(QPainter::Antialiasing);
	p.setRenderHint(QPainter::SmoothPixmapTransform);
	p.fillRect(rect, QColor("#00AA00"));

	// draw background
	if ((locker_.status & zl::ELockerStatus_Occupied) != 0x00)
        p.fillRect(rect, QColor("#FFD39B"));
	if ((locker_.status & zl::ELockerStatus_Error) != 0x00)
		p.fillRect(rect, QColor("#55007F"));
	if ((locker_.status & zl::ELockerStatus_Locked) != 0x00)
		p.fillRect(rect, QColor("#FF0000"));

	// draw box no	
	p.save();
    QFont font;
    font.setPointSize(10);
	p.setFont(font);
    p.setPen(QColor("#FFFFFF"));
    p.drawText(QPoint(5, 20), get_locker_no_string(tag_number_ + locker_.boxno));
    p.drawText(QPoint(5, DEFAULT_CELL_HEIGHT - 8), get_locker_size_string(locker_.type));
	p.restore();

    // door status
	if ((locker_.status & zl::ELockerStatus_Door) != 0x00)
    {
        p.fillRect(
            QRect(DEFAULT_CELL_WIDHT - 20, 10, 10, DEFAULT_CELL_HEIGHT - 20),
            QColor("#000000"));
    }

    // item status
	if ((locker_.status & zl::ELockerStatus_Item) != 0x00)
	{
		QPainterPath path;
        path.addEllipse(QPoint(DEFAULT_CELL_WIDHT / 2, DEFAULT_CELL_HEIGHT / 2), 15, 15);
		p.fillPath(path, QColor("#000000"));
	}

	if (this->isChecked())
	{
		QPainterPath p1, p2;
        p1.addRect(0, 0, DEFAULT_CELL_WIDHT, DEFAULT_CELL_HEIGHT);
        p2.addRect(3, 3, DEFAULT_CELL_WIDHT - 6, DEFAULT_CELL_HEIGHT - 6);
		p.fillPath(p1 - p2, QColor("#000000"));
	}
}

void CCustomBoxCell::show()
{
	is_visiable_ = true;
	QPushButton::show();
}

void CCustomBoxCell::hide()
{
	is_visiable_ = false;
	QPushButton::hide();
}

///////////////////////////////////////////////////////
CCustomBoxView::CCustomBoxView(QWidget * parent)
	: QWidget(parent)
	, btn_group_(new QButtonGroup(this))
{
	init();
    setMouseTracking(true);
	// connect
	connect(btn_group_, SIGNAL(buttonClicked(int)), this, SIGNAL(boxClicked(int)));
}

CCustomBoxView::~CCustomBoxView()
{

}

void CCustomBoxView::SetLayout(const zl::LockerLayout& layout)
{
	hide_all();
	int32_t max_cnt = 0;
	int32_t max_col_cnt = 0;
    for (auto& l : layout)
    {
        max_cnt += l.typestr.size();
        max_col_cnt = max_col_cnt > l.typestr.size() ? max_col_cnt : l.typestr.size();
    }

	resize_btngroup(max_cnt);
	setFixedWidth(layout.size() * (DEFAULT_CELL_WIDHT + DEFAULT_SPACING) + DEFAULT_SPACING);
	setFixedHeight(max_col_cnt * (DEFAULT_CELL_HEIGHT + DEFAULT_SPACING) + DEFAULT_SPACING);

	int index = 0;
    for (size_t col = 0; col < layout.size(); ++col)
	{
        for (int row = 0; row < layout[col].typestr.size(); ++row)
		{
			auto cell = cells_[index];
			int y = row * (DEFAULT_CELL_HEIGHT + DEFAULT_SPACING) + DEFAULT_SPACING;
			int x = col * (DEFAULT_CELL_WIDHT + DEFAULT_SPACING) + DEFAULT_SPACING;
			cell->move(x, y);
			index++;
		}
	}
}

void CCustomBoxView::SetData(const zl::LockerVec& lockers, int32_t tag_number)
{
	int cnt = lockers.size() > cells_.size() ? cells_.size() : lockers.size();
	for (int i = 0; i < cnt; ++i)
	{
		auto cell = cells_[i];
		cell->SetData(lockers[i]);
        cell->SetTagNumber(tag_number);
		cell->show();
	}
}

void CCustomBoxView::init()
{
	btn_group_->setExclusive(true);
	for (int i = 0; i < DEFAULT_MAX_BOX_CNT; ++i)
	{
		auto cell = new CCustomBoxCell(this);
		cell->setCheckable(true);
		cell->setFixedSize(DEFAULT_CELL_WIDHT, DEFAULT_CELL_HEIGHT);
        cell->setMouseTracking(true);
        cell->installEventFilter(this);
		cell->hide();
		btn_group_->addButton(cell, i + 1);
		cells_.push_back(cell);
	}
}

void CCustomBoxView::hide_all()
{
	std::for_each(cells_.begin(), cells_.end(), [&](CCustomBoxCell* c) {
		c->hide();
		c->setChecked(false);
	});
}

void CCustomBoxView::resize_btngroup(int32_t size)
{
    if ((size_t)size < cells_.size())
	{
		return;
	}

	for (int i = cells_.size(); i < size; ++i)
	{
		auto cell = new CCustomBoxCell(this);
		cell->setCheckable(true);
		cell->setFixedSize(DEFAULT_CELL_WIDHT, DEFAULT_CELL_HEIGHT);
		cell->hide();
		cells_.push_back(cell);
		btn_group_->addButton(cell, i + 1);
	}
}

bool CCustomBoxView::eventFilter(QObject *watched, QEvent *event)
{
    if (qobject_cast<CCustomBoxCell*>(watched) != Q_NULLPTR)
    {
        QWidget::eventFilter(watched, event);
        if (event->type() == QEvent::MouseButtonPress)
        {
            flag_drag_ = true;
            flag_drag_continue_ = false;
            QMouseEvent* e = (QMouseEvent*)event;
            drag_posx_ = e->globalPos().x();
            drag_posy_ = e->globalPos().y();
        }
        else if (event->type() == QEvent::MouseButtonRelease)
        {
            flag_drag_ = false;
        }
        else if (event->type() == QEvent::MouseMove)
        {
            QMouseEvent* e = (QMouseEvent*)event;
            QScrollArea* wa = qobject_cast<QScrollArea*>(this->parent()->parent());
            if (wa == Q_NULLPTR || e == Q_NULLPTR || !flag_drag_)
            {
                return true;
            }

            QScrollBar* barx = wa->horizontalScrollBar();
            QScrollBar* bary = wa->verticalScrollBar();
            QPoint p = e->globalPos();
            int offsetx = p.x() - drag_posx_;
            int offsety = p.y() - drag_posy_;
            if (!flag_drag_continue_ && qAbs(offsetx) < 10 && qAbs(offsety) < 10)
            {
                return true;
            }

            flag_drag_continue_ = true;
            drag_posx_ = p.x();
            drag_posy_ = p.y();
            if (barx != Q_NULLPTR)
            {
                barx->setValue(barx->value() - offsetx);
            }
            if (bary != Q_NULLPTR)
            {
                bary->setValue(bary->value() - offsety);
            }
        }
    }

    return QWidget::eventFilter(watched, event);
}

void CCustomBoxView::mousePressEvent(QMouseEvent *e)
{
    flag_drag_ = true;
    flag_drag_continue_ = false;
    drag_posx_ = e->globalPos().x();
    drag_posy_ = e->globalPos().y();
    return QWidget::mousePressEvent(e);
}

void CCustomBoxView::mouseMoveEvent(QMouseEvent *e)
{
    if (!flag_drag_)
    {
        return;
    }

    QScrollArea* wa = qobject_cast<QScrollArea*>(this->parent()->parent());
    if (wa == Q_NULLPTR)
    {
        return QWidget::mouseMoveEvent(e);
    }

    QScrollBar* barx = wa->horizontalScrollBar();
    QScrollBar* bary = wa->verticalScrollBar();
    QPoint p = e->globalPos();
    int offsetx = p.x() - drag_posx_;
    int offsety = p.y() - drag_posy_;
    if (!flag_drag_continue_ && qAbs(offsetx) < 10 && qAbs(offsety) < 10)
    {
        return;
    }

    flag_drag_continue_ = true;
    drag_posx_ = p.x();
    drag_posy_ = p.y();
    if (barx != Q_NULLPTR)
    {
        barx->setValue(barx->value() - offsetx);
    }
    if (bary != Q_NULLPTR)
    {
        bary->setValue(bary->value() - offsety);
    }
}

void CCustomBoxView::mouseReleaseEvent(QMouseEvent *e)
{
    flag_drag_ = false;
    return QWidget::mouseReleaseEvent(e);
}
